package com.zhenai.sys.framework.aspectj;

import com.zhenai.bcus.common.base.utils.PhoneUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/** 参数名含 keyword 或 phone 或 mobile 的，在 sys-user 弄一个AOP拦截，统一加密此参数的值
 * @author ouxuxuan
 * @date 2024/7/1 18:07
 */
//@Aspect
//@Component
@Slf4j
public class EncryptPhoneAspect {

        static List<String> PHONE_KEYWORDS = Arrays.asList("keyword");

        /**
         * @description
         * @param paramNames:
         * @param paramValues:
         * @return void
         * @author ouxuxuan
         * @date 2023/9/15 17:58
         */
        private void setFromBasic(String[] paramNames, Object[] paramValues, String fieldName){
            for(int i=0; i < paramNames.length; i++){
                String name = paramNames[i];
                if(StringUtils.isNotEmpty(name) && name.contains(fieldName)){
                    if(!Objects.isNull(paramValues[i]) && paramValues[i] instanceof String){
                        paramValues[i] = PhoneUtils.encryptPhone(paramValues[i].toString());
                    }
                }
            }
        }

        private void setFromBeanType(Object[] paramValues, String fieldName) {
            for(Object param : paramValues){
                if(Objects.isNull(param)){
                    continue;
                }
                setFieldValue(param, fieldName);
            }
        }


        /**
         * @description <获取自定义对象某个字段的值，没有该字段的话则返回Null>
         * @param obj:
         * @param fieldName:
         * @return boolean
         * @author ouxuxuan
         * @date 2023/9/15 18:06
         */
        public Object setFieldValue(Object obj, String fieldName) {
            try {
                Class<?> clazz = obj.getClass();
                Field field = getDeclaredField(clazz, fieldName);
                if (Objects.isNull(field)) { // 从父类获取
                    field = getDeclaredField(clazz.getSuperclass(), fieldName);
                }
                if (field != null) {
                    field.setAccessible(true);
                    try {
                        final Object phone = field.get(obj);
                        if (!Objects.isNull(phone)  && (phone instanceof String)) {
                            field.set(obj, PhoneUtils.encryptPhone(phone.toString()));
                            return obj;
                        }
                    } catch (IllegalAccessException e) {
                        return null;
                    }
                }
            }
            catch (Exception e) {
                log.error("获取自定义对象某个字段的值失败", e);
            }
            return null;
        }

        private Field getDeclaredField(Class<?> clazz, String fieldName) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (field.getName().equals(fieldName)) {
                    return field;
                }
            }
            return null;
        }

        @Around("@annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.PutMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping)")
        public Object intercept(ProceedingJoinPoint joinPoint) throws Throwable {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            String[] paramNames = signature.getParameterNames();
            Object[] paramValues = joinPoint.getArgs();

            for(String fieldName : PHONE_KEYWORDS){
                setFromBasic(paramNames, paramValues, fieldName);
                setFromBeanType(paramValues, fieldName);
            }

            try {
                if(paramValues != null && paramValues.length > 0){
                    return joinPoint.proceed(paramValues);
                } else {
                    return joinPoint.proceed();
                }
            } catch (Throwable e) {
                throw e;
            }
        }

}
